require "prefabutil"

local cooking = require("cooking")

local assets =
{
    Asset("ANIM", "anim/tf_cookpot.zip"),
    Asset("ANIM", "anim/cook_pot_food.zip"),
    Asset("ANIM", "anim/ui_cookpot_1x4.zip"),
}

local prefabs =
{
    "collapse_small",
}

for k, v in pairs(cooking.recipes.cookpot) do
    table.insert(prefabs, v.name)

    if v.overridebuild then
        table.insert(assets, Asset("ANIM", "anim/" .. v.overridebuild .. ".zip"))
    end
end

-- 状态判断
local function upgraded(inst)
    if inst.upgraded == 0 then
        return
    elseif inst.upgraded == 1 then
        inst.components.constructionsite:Enable()
    elseif inst.upgraded == 2 then
        inst.components.constructionsite:Disable()
        inst:RemoveTag("tf_cookpot_upgrad")
    end
end

-- 升级机制：使用 constructionsite 模拟隐士之家建造升级
local function OnConstructed(inst, doer)
    local concluded = true
    for _, v in ipairs(CONSTRUCTION_PLANS[inst.prefab] or {}) do
        if inst.components.constructionsite:GetMaterialCount(v.type) < v.amount then
            concluded = false
            break
        end
    end

    if concluded then
        inst.upgraded = 2
        upgraded(inst)
        local fx = SpawnPrefab("collapse_small")
        fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
        fx:SetMaterial("metal")
    end
end

local function onhammered(inst, worker)
    if inst.components.stewer.product ~= nil and inst.components.stewer:IsDone() then
        inst.components.stewer:Harvest()
    end
    if inst.components.container ~= nil then
        inst.components.container:DropEverything()
    end
    inst.components.lootdropper:DropLoot()
    local fx = SpawnPrefab("collapse_small")
    fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
    fx:SetMaterial("metal")
    inst:Remove()
end

local function onhit(inst, worker)
    if inst.components.stewer:IsCooking() then
        inst.AnimState:PlayAnimation("hit_cooking")
        inst.AnimState:PushAnimation("cooking_loop", true)
        inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
    elseif inst.components.stewer:IsDone() then
        inst.AnimState:PlayAnimation("hit_full")
        inst.AnimState:PushAnimation("idle_full", false)
    else
        if inst.components.container ~= nil and inst.components.container:IsOpen() then
            inst.components.container:Close()
        else
            inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
        end
        inst.AnimState:PlayAnimation("hit_empty")
        inst.AnimState:PushAnimation("idle_empty", false)
    end
end

-- 动画和声音播放回调

local function startcookfn(inst)
    inst.AnimState:PlayAnimation("cooking_loop", true)
    inst.SoundEmitter:KillSound("snd")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_rattle", "snd")
    inst.Light:Enable(true)
end

local function onopen(inst)
    inst.AnimState:PlayAnimation("cooking_pre_loop")
    inst.SoundEmitter:KillSound("snd")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_open")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot", "snd")
end

local function onclose(inst)
    if not inst.components.stewer:IsCooking() then
        inst.AnimState:PlayAnimation("idle_empty")
        inst.SoundEmitter:KillSound("snd")
    end
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
end

local function SetProductSymbol(inst, product, overridebuild)
    local recipe = cooking.GetRecipe(inst.prefab, product)
    local potlevel = recipe ~= nil and recipe.potlevel or nil
    local build = (recipe ~= nil and recipe.overridebuild) or overridebuild or "cook_pot_food"
    local overridesymbol = (recipe ~= nil and recipe.overridesymbolname) or product

    if potlevel == "high" then
        inst.AnimState:Show("swap_high")
        inst.AnimState:Hide("swap_mid")
        inst.AnimState:Hide("swap_low")
    elseif potlevel == "low" then
        inst.AnimState:Hide("swap_high")
        inst.AnimState:Hide("swap_mid")
        inst.AnimState:Show("swap_low")
    else
        inst.AnimState:Hide("swap_high")
        inst.AnimState:Show("swap_mid")
        inst.AnimState:Hide("swap_low")
    end

    inst.AnimState:OverrideSymbol("swap_cooked", build, overridesymbol)
end

local function spoilfn(inst)
    inst.components.stewer.product = inst.components.stewer.spoiledproduct
    SetProductSymbol(inst, inst.components.stewer.product)
end

local function ShowProduct(inst)
    local product = inst.components.stewer.product
    SetProductSymbol(inst, product, not TF_TOOL_IsNativeCookingProduct(product) and product or nil)
end

local function donecookfn(inst)
    inst.AnimState:PlayAnimation("cooking_pst")
    inst.AnimState:PushAnimation("idle_full", false)
    ShowProduct(inst)
    inst.SoundEmitter:KillSound("snd")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_finish")
    inst.Light:Enable(false)
end

local function continuedonefn(inst)
    inst.AnimState:PlayAnimation("idle_full")
    ShowProduct(inst)
end

local function continuecookfn(inst)
    inst.AnimState:PlayAnimation("cooking_loop", true)
    inst.Light:Enable(true)
    inst.SoundEmitter:KillSound("snd")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_rattle", "snd")
end

local function harvestfn(inst)
    inst.AnimState:PlayAnimation("idle_empty")
    inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
end

local function getstatus(inst)
    return (inst.components.stewer:IsDone() and "DONE")
        or (not inst.components.stewer:IsCooking() and "EMPTY")
        or (inst.components.stewer:GetTimeToCook() > 15 and "COOKING_LONG")
        or "COOKING_SHORT"
end

local function onbuilt(inst)
    inst.AnimState:PlayAnimation("place")
    inst.AnimState:PushAnimation("idle_empty", false)
    inst.SoundEmitter:PlaySound("dontstarve/common/cook_pot_craft")
end

local function onsave(inst, data)
    data.upgraded = inst.upgraded
end

local function onload(inst, data)
    if data and data.upgraded then
        inst.upgraded = data.upgraded
        upgraded(inst)
    end
end

local function onloadpostpass(inst, newents, data)
    if data and data.additems and inst.components.container then
        for i, itemname in ipairs(data.additems) do
            local ent = SpawnPrefab(itemname)
            inst.components.container:GiveItem(ent)
        end
    end
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddMiniMapEntity()
    inst.entity:AddLight()
    inst.entity:AddNetwork()

    inst:SetDeploySmartRadius(1)
    MakeObstaclePhysics(inst, .5)

    inst.Light:Enable(false)
    inst.Light:SetRadius(.6)
    inst.Light:SetFalloff(1)
    inst.Light:SetIntensity(.5)
    inst.Light:SetColour(235 / 255, 62 / 255, 12 / 255)

    inst:AddTag("structure")
    inst:AddTag("stewer") -- 可制作料理标签
    inst:AddTag("constructionsite")
    inst:AddTag("stack_cook") -- 兼容批量烹饪mod的标签

    if TUNING.TF_COOKPOT == "Yes" then
        inst:AddTag("tf_cookpot_upgrad")
    end

    inst.AnimState:SetBank("tf_cookpot")
    inst.AnimState:SetBuild("tf_cookpot")
    inst.AnimState:PlayAnimation("idle_empty")
    inst.MiniMapEntity:SetIcon("tf_cookpot.tex")

    MakeSnowCoveredPristine(inst)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst.upgraded = 0
    inst:AddComponent("stewer")
    inst.components.stewer.onstartcooking = startcookfn       -- 开始烹饪函数
    inst.components.stewer.oncontinuecooking = continuecookfn -- 继续烹饪的函数
    inst.components.stewer.oncontinuedone = continuedonefn    -- 结束烹饪函数(貌似是加载范围外)
    inst.components.stewer.ondonecooking = donecookfn         -- 结束烹饪函数
    inst.components.stewer.onharvest = harvestfn              -- 收获函数
    inst.components.stewer.onspoil = spoilfn                  -- 腐烂函数

    inst:AddComponent("container")
    inst.components.container:WidgetSetup("tf_cookpot")
    inst.components.container.onopenfn = onopen
    inst.components.container.onclosefn = onclose
    inst.components.container.skipclosesnd = true
    inst.components.container.skipopensnd = true

    inst:AddComponent("inspectable")
    inst.components.inspectable.getstatus = getstatus

    inst:AddComponent("tf_build")

    inst:AddComponent("constructionsite")
    inst.components.constructionsite:SetConstructionPrefab("construction_container")
    inst.components.constructionsite:SetOnConstructedFn(OnConstructed)
    inst.components.constructionsite:Disable()

    inst:AddComponent("lootdropper")
    inst:AddComponent("workable")
    inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
    inst.components.workable:SetWorkLeft(4)
    inst.components.workable:SetOnFinishCallback(onhammered)
    inst.components.workable:SetOnWorkCallback(onhit)

    inst:AddComponent("hauntable")
    inst.components.hauntable:SetHauntValue(TUNING.HAUNT_TINY)

    MakeSnowCovered(inst)
    inst:ListenForEvent("onbuilt", onbuilt)

    inst.OnSave = onsave
    inst.OnLoad = onload
    inst.OnLoadPostPass = onloadpostpass

    return inst
end

return Prefab("tf_cookpot", fn, assets, prefabs),
    MakePlacer("tf_cookpot_placer", "tf_cookpot", "tf_cookpot", "idle_empty")
